package com.kclm.se.nio.demo;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;
import java.util.Set;

/*****
 * 
 * @author yejf
 * @since JDK8.0
 * @CreateDate 2020年9月14日 下午5:57:11 
 * @description 此类用来描述了多路复用器的使用
 *
 */
public class NioServer {

	private final int PORT = 9292;
	/** 缓存区大小 */
	private final int BLOCK = 4096;
	/** 接收数据缓存区 */
	private ByteBuffer receiveBuf = ByteBuffer.allocate(BLOCK);
	/** 发送数据缓存区 */
	private ByteBuffer sendBuf = ByteBuffer.allocate(BLOCK);
	/** 多路复用器 */
	private Selector selector;
	
	public NioServer() throws Exception {
		//创建 ServerSocketChannel对象
		ServerSocketChannel ssc = ServerSocketChannel.open();
		//绑定端口
		ssc.bind(new InetSocketAddress(PORT));
		//配置为非阻塞
		ssc.configureBlocking(false);
		//初始化 选择器/多路复用器
		this.selector = Selector.open();
		//把此 server 注册到选择器中
		ssc.register(this.selector, SelectionKey.OP_ACCEPT);
		//注：上面注册的 key就是 ServerSocketChannel, 可以通过返回值来获取
		//...
		System.out.printf("服务器已经启动，在端口：%d监听\n", PORT);
	}
	
	/*****
	 * 服务器监听并处理客户端的连接
	 */
	public void listen() throws Exception {
		//
		while(true) {
			System.out.printf("此时注册的Channel有【%d】路.\n", this.selector.keys().size());
			//通过选择器来“选择”要处理的 channel
			while(this.selector.select() > 0) { //注：select() 方法是一个阻塞方法【可以指定超时时间，单位毫秒】
				//获取所有的 SelectionKey
				Set<SelectionKey> keys = this.selector.selectedKeys();
				//迭代
				Iterator<SelectionKey> iter = keys.iterator();
				//
				while(iter.hasNext()) {
					//获取每一个 SelectionKey, 也就是连接上来的 Channel
					SelectionKey selectionKey = iter.next();
					//判断
					if(selectionKey.isAcceptable()) {
						//
						System.out.println("Acceptable.....");
						//
						
					}
				}
			}
		}
	}
}
